package ch.fusun.baron.unit.service;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import ch.fusun.baron.data.AbstractDataProvider;
import ch.fusun.baron.map.Tile;
import ch.fusun.baron.unit.Unit;

/**
 * The unit service implementation
 */
public class UnitServiceImpl extends AbstractDataProvider implements
		UnitService {
	private Map<Tile, Collection<Unit>> tileUnitMap = new HashMap<Tile, Collection<Unit>>();
	private int index = 0;

	/**
	 * Injection constructor
	 */
	public UnitServiceImpl() {
	}

	@Override
	public UnitDataUpdate createFullUpdate() {
		return new UnitDataUpdate(tileUnitMap, index);
	}

	@Override
	public Collection<Unit> getUnits(Tile tile) {
		if (tileUnitMap.get(tile) == null) {
			tileUnitMap.put(tile, new LinkedList<Unit>());
		}
		return tileUnitMap.get(tile);
	}

	@Override
	public Unit createUnit(Tile location, int numberOfUnits) {
		Unit unit = new Unit(getNextId(), numberOfUnits);
		addUnitToLocation(location, unit);
		return unit;
	}

	private int getNextId() {
		return index++;
	}

	@Override
	public void addUnitToLocation(Tile location, Unit unit) {
		getUnits(location).add(unit);
		updateAllListeners(new AddUnitToLocation(location, unit));
	}

	@Override
	public void setUnitMap(Map<Tile, Collection<Unit>> tileUnitMap) {
		this.tileUnitMap = tileUnitMap;
		updateAllListeners(new UnitDataUpdate(tileUnitMap, index));
	}

	@Override
	public Tile getLocation(Unit unit) {
		for (Tile tile : tileUnitMap.keySet()) {
			Collection<Unit> units = getUnits(tile);
			if (units.contains(unit)) {
				return tile;
			}
		}
		return null;
	}

	@Override
	public void moveUnit(Unit unit, Tile destination) {
		Tile location = getLocation(unit);
		if (location != null) {
			removeUnit(unit);
			addUnitToLocation(destination, unit);
		}
	}

	@Override
	public boolean unitExists(Unit unit) {
		for (Tile tile : tileUnitMap.keySet()) {
			Collection<Unit> units = getUnits(tile);
			if (units.contains(unit)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void removeUnit(Unit unit) {
		Tile location = getLocation(unit);
		Collection<Unit> units = getUnits(location);
		units.remove(unit);
		updateAllListeners(new RemoveUnitDataUpdate(unit));
	}

	@Override
	public Collection<Unit> getAllUnits() {
		Collection<Unit> allUnits = new LinkedList<Unit>();
		for (Collection<Unit> units : tileUnitMap.values()) {
			allUnits.addAll(units);
		}
		return allUnits;
	}

	@Override
	public void setIndex(int index) {
		this.index = index;
	}

}
